iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0

防止 XSS 和 CSRF 攻擊


XSS
XSS (Cross-Site Scripting) 是一種攻擊技術,攻擊者將惡意腳本注入到正常的網頁中。當其他用戶訪問這個網頁時,這些腳本會在用戶的瀏覽器中執行,從而達到竊取用戶信息或進行其他惡意操作的目的,影響的是用戶的安全性。

CSRF
CSRF (Cross-Site Request Forgery) 是一種攻擊方式,攻擊者利用已登錄用戶的身份發送未經授權的請求;例如,如果用戶已經登錄某個網站,攻擊者可以誘使用戶點擊一個鏈接,該鏈接會發送請求到該網站,可能會執行不應該的操作,就像轉帳、改密碼等...,所以影響的是網站的安全性。

預防方法

  1. 最小化攻擊面
    減少暴露給客戶端的程式碼量以限制潛在的漏洞,也就是盡可能將敏感邏輯和資料處理移至伺服器端;對應用程式的關鍵部分使用伺服器端渲染。

    <!-- 不必要的引入應該避免 -->
    <!-- 不要這樣做 -->
    <script src="https://all_come_on-library.js"></script>
    
    <!-- 只引入必要 -->
    <script src="https://i_need-library.js"></script>
    
    function submitData(data) {
      fetch("/api/submit", {
        method: "POST",
        body: JSON.stringify(data)
      })
        .then((response) => response.json())
    
        .then((responseData) => {
          console.log("11_資料提交成功::", responseData);
        })
    
        .catch((error) => {
          console.error("00_提交資料出現例外::", error);
        });
    }
    
  2. 使用安全隨機數
    對會話令牌或加密等任務採用加密安全隨機數產生。
    出於安全敏感目的,避免使用基於瀏覽器的 Math.random(),可以在環境中使用 crypto (Node.js) 等函式庫或安全性替代方案。

    // 使用 Crypto API 生成安全隨機數
    function generateSecureToken() {
        const array = new Uint32Array(10);
        window.crypto.getRandomValues(array);
        return Array.from(array, num => num.toString(36)).join('');
    }
    
  3. 實施 CSRF 保護 -> 這是剛開始學後端用畫面觀察 api 回傳很常會用到的方法

    參考文章:後端小白自學 Laravel - 第 9 天:表單處理與請求

    使用 CSRF 令牌防止未經授權的表單提交,為每個使用者會話產生唯一的 CSRF 令牌。將令牌包含在表單中並在伺服器端驗證它以防止 CSRF 攻擊。

    <form method="POST" action="/submit">
        <input type="hidden" name="csrf_token" value="your_csrf_token_here">
        <input type="text" name="data">
        <input type="submit" value="提交">
    </form>
    
    fetch('/submit', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'CSRF-Token': 'your_csrf_token_here'
        },
        body: JSON.stringify({ data: 'some data' })
    });
    
  4. 避免內聯事件處理程序
    對事件偵聽器使用單獨的函數,以防止注入程式碼中的 XSS,可以用 JavaScript 函數附加事件偵聽器,而不是在 HTML 中使用 onclick 屬性。

    <!-- 不建議的內聯事件處理 -->
    <button onclick="handleClick()">Click me</button>
    
    <!-- 改為使用事件監聽器 -->
    <button id="myButton">Click me</button>
    <script>
        document.getElementById('myButton').addEventListener('click', handleClick);
    </script>
    
  5. 使用內容安全策略 (CSP)
    在伺服器上設定 CSP 標頭以限制應用程式可以從何處載入資源。

    // 在 HTTP 頭中設置 CSP
    Content-Security-Policy: default-src 'self'; script-src 'self'; img-src 'self' data:;
    

安全的使用者輸入和資料處理


無論是在前端還是後端,安全的使用者輸入和資料處理都是相當重要的,先前的我會覺得這是後端的工作,伺服器把關不是更好嗎?!轉後端後,覺得不能把責任都丟給後端,畢竟前後一家親,網頁多一道把關,開發晚上才能睡好覺,不是嗎?

那怎麼把關呢?方法百百種,只要能解決問題都是好方法!

前端 JavaScript 負責驗證和消毒用戶輸入,而 Laravel 則提供了強大的驗證和處理機制,可以確保應用程序的安全性;這樣的雙重防護可以有效地降低風險提升網站安全性。

前端 JavaScript 角度

  1. 輸入驗證
    在提交表單之前,進行基本的格式驗證,例如,檢查電子郵件格式或確保輸入不為空。

    阻止事件參考文章:第 21 天:JavaScript 的事件處理和他的 DOM - 事件物件

    function validateForm() {
        const email = document.getElementById('email').value;
        const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    
        if (!regex.test(email)) {
            alert('請輸入有效的電子郵件地址。');
            return false;
        }
        return true;
    }
    
    document.getElementById('myForm').addEventListener('submit', function(event) {
        if (!validateForm()) {
            event.preventDefault(); // 阻止表單提交
        }
    });
    

    當然也可以用 HTML5 的方法

    MDN 文件:表单数据校验

    <input type="text" id="name" name="name" required>
    <input type="text" required="required" maxlength="11" pattern="09\d{2}-\d{6}"/>
    <input type="email" required="required" pattern="[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$"/>
    
  2. 輸入消毒
    消毒用戶輸入以防止 XSS 攻擊,就像使用一個簡單的函數來移除 HTML 標籤。

    function sanitizeInput(input) {
        const div = document.createElement('div');
        div.innerText = input; // 將文本設置為內部文本
        return div.innerHTML; // 返回消毒後的 HTML
    }
    
    const sanitizedInput = sanitizeInput(userInput);
    
  3. 錯誤處理
    在發送請求之前和之後,進行適當的錯誤處理,以提高用戶體驗。

    fetch('/api/submit', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ data: sanitizedInput })
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('網絡錯誤!');
        }
        return response.json();
    })
    .then(data => {
        console.log('成功:', data);
    })
    .catch(error => {
        alert('發生錯誤:' + error.message);
    });
    

後端 Laravel 角度 -> 請原諒我現在只會這個!

  1. 輸入驗證
    使用 Laravel 的表單請求進行驗證。

    參考文章:後端小白自學 Laravel - 第 9 天:表單處理與請求 & 第 18 天:驗證與自定義規則

    // App\Http\Requests\StoreUserRequest.php
    namespace App\Http\Requests;
    
    use Illuminate\Foundation\Http\FormRequest;
    
    class StoreUserRequest extends FormRequest
    {
        public function rules()
        {
            return [
                'email' => 'required|email',
                'name'  => 'required|string|max:255',
            ];
        }
    
        public function authorize()
        {
            return true; // 授權
        }
    }
    
    // 在 Controller 中使用這個請求
    public function store(StoreUserRequest $request)
    {
        // 驗證通過,進行資料處理
        User::create($request->validated());
    }
    
  2. 輸入消毒
    Laravel 會自動處理基本的輸入消毒。例如,使用 strip_tags 去除 HTML 的字串內容。-> 因為 laravel10.x 以後才有這個功能,在這之前其實沒有特別去注意這段!

    文件:Strings - 函數剝去字串中的 HTML、XML 以及 PHP 的標籤

    use Illuminate\Support\Str;
    
    $result = Str::of('<a href="https://laravel.com">Taylor <b>Otwell</b></a>')->stripTags();
    
    // Taylor Otwell
    
    $result = Str::of('<a href="https://laravel.com">Taylor <b>Otwell</b></a>')->stripTags('<b>');
    
    // Taylor <b>Otwell</b>
    
  3. 錯誤處理
    在 Laravel 中,透過表單驗證處理例外情況,並返回適當的錯誤響應。

    // 在控制器中
    public function store(StoreUserRequest $request)
    {
        try {
            User::create($request->validated());
    
            return response()->json(['message' => '用戶創建成功'], 201);
        } catch (\Exception $e) {
            return response()->json(['error' => '發生錯誤:' . $e->getMessage()], 500);
        }
    }
    

    還記得第 11 天:API 與 Axios - 網路狀態碼提到學後端之後發現,這些狀態碼用於指示請求的處理結果,對於後端的測試很重要,這裡也是重要的原因之一!

    另外,HTTP 狀態碼對於 SEO(搜尋引擎優化)有直接影響,因為搜尋引擎在爬取和索引網站時會根據這些狀態碼來判斷網頁的可訪問性和有效性。

    HTTP 狀態碼 狀態 狀態解釋 對 SEO 影響
    200 OK 請求成功,搜尋引擎會將該頁面正常索引 搜尋引擎會將該頁面正常索引,對 SEO 有正面影響
    301 Moved Permanently 表示頁面已永久移動到新位置 將權重傳遞到新頁面,有利於保持 SEO 排名
    302 Found 頁面臨時移動 不會傳遞權重
    404 Not Found 頁面未找到 網站上有大量 404 錯誤,會影響用戶體驗和搜尋引擎的評價,可能導致排名下降
    500 Internal Server Error 伺服器發生錯誤 如果頻繁出現,會影響網站的爬取和索引,對 SEO 有負面影響

上一篇
第 25 天:JavaScript 的 Clean Code
下一篇
第 27 天:資料存儲與處理
系列文
30天 JavaScript 提升計畫:從零到精通結合2024年的創新功能30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言